import wx
from audio import *
from pyo import *
from wx.lib.scrolledpanel import ScrolledPanel




class MainFrame(wx.Frame):
    def __init__(self, parent, id=-1, title="tr-3535", pos=(0,25), size=(850,700)):
        wx.Frame.__init__(self, parent, id, title, pos, size)
        self.SetMaxSize((850, -1))
        self.SetMinSize((850, -1))
        
        self.path = ""
        
        # creation du serveur audio
        self.server = AudioServer()
        self.server.controlVolume(.75)
        
        self.mainPanel = wx.Panel(self)
        self.bbox = wx.BoxSizer(wx.VERTICAL)
        #controles generaux
        
        self.generalPanel = wx.Panel(self.mainPanel)
        self.bbox.Add(self.generalPanel, 0)
        
        self.onOff = wx.ToggleButton(self.generalPanel, id=-1, label="On / Off", pos=(25,25), size= (75, 20))
        self.onOff.Bind(wx.EVT_TOGGLEBUTTON, self.handleAudio)

        self.bpm = Sig(120) 
        self.bpmText = wx.StaticText(self.generalPanel, id=-1, label="BPM", pos=(115, 25), size=wx.DefaultSize)
        self.bpmCtrl = wx.SpinCtrl(self.generalPanel, id=-1, value="120", pos=(140, 20), size=wx.DefaultSize, min=0, max=400, initial=120)
        self.bpmCtrl.Bind(wx.EVT_SPINCTRL, self.changeBpm)
        
        self.masterVol = wx.StaticText(self.generalPanel, id=-1, label="Master", pos=(225, 25), size=wx.DefaultSize)
        self.masterFader = wx.Slider(self.generalPanel, id=-1, value=75, minValue=0, maxValue=100, pos=(275,25), size=(100, 25))
        self.masterFader.Bind(wx.EVT_SLIDER, self.masterVolume)
        
        self.masterClick= Metro(60./self.bpm/4, poly=2).stop()
        

        #controles d'instruments    
        self.modulesPanel = ScrolledPanel(self.mainPanel, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.SB_VERTICAL)
        self.modulesPanel.SetAutoLayout(1)
        self.modulesPanel.SetupScrolling()
        self.bbox.Add(self.modulesPanel, 1, wx.EXPAND|wx.ALL, 5)
        
        self.modulesBoxSizer = wx.BoxSizer(wx.VERTICAL)
        
        self.mainPanel.SetSizer(self.bbox)
        self.modulesPanel.SetSizer(self.modulesBoxSizer)
        
        self.modules = ["KICK", "SNARE"]

        # creation du menu        
        menubar = wx.MenuBar()
        
        fileMenu = wx.Menu() 

        fileMenu.Append(wx.ID_OPEN, "Open\tCtrl+O")
        self.Bind(wx.EVT_MENU, self.open, id=wx.ID_OPEN)

        fileMenu.Append(wx.ID_SAVE, "Save\tCtrl+S")
        self.Bind(wx.EVT_MENU, self.save, id=wx.ID_SAVE)

        fileMenu.Append(wx.ID_SAVEAS, "Save As...\tShift+Ctrl+S")
        self.Bind(wx.EVT_MENU, self.saveAs, id=wx.ID_SAVEAS)

        fileMenu.Append(wx.ID_EXIT, "Quit\tCtrl+Q")
        self.Bind(wx.EVT_MENU, self.onQuit, id=wx.ID_EXIT)
        self.Bind(wx.EVT_CLOSE, self.onQuit)

        self.moduleMenu = wx.Menu()
        for i, mod in enumerate(self.modules):
            self.moduleMenu.Append(i+100, mod+"\tCtrl+%d" % (i+1))
            self.Bind(wx.EVT_MENU, self.createModule, id=i+100)
        fileMenu.AppendMenu(-1, "Modules", self.moduleMenu)
        fileMenu.AppendSeparator()
        fileMenu.Append(wx.ID_EXIT, "Quit\tCtrl+Q")
        menubar.Append(fileMenu, "File")
        
        self.SetMenuBar(menubar)
        self.Show()
        
    def masterVolume(self, evt):
        x = evt.GetInt()/100.
        self.server.controlVolume(x)
        
    def getStateDictionary(self):
        statesDict = {}
        modules = self.server.getProject()
        general = [self.bpm.value, self.masterFader.GetValue()]
        names = [module.name for module in modules]
        states = [module.getState() for module in modules]
        statesDict["general"] = general
        statesDict["modules"] = names
        statesDict["states"] = states
        return statesDict
        
    def setStateDictionary(self, dict):
        names = stateDictionary["modules"]
        states = stateDictionary["states"]
        genParam = stateDictionary["general"]
        self.bpm.setValue(genParam[0])
        self.bpmCtrl.SetValue(genParam[0])
        self.masterFader.SetValue(genParam[1])
        for i in range(len(names)):
            self.addModulesFromSave(rank=i, name=names[i], state=states[i])
            
    def addModulesFromSave(self, rank, name, state):
        moduleRank = rank
        moduleName = name
        statesList = state
        self.module = InstInterface(
                                    self.modulesPanel, metro=self.masterClick, y=moduleRank, type=dict[moduleName], 
                                    name=moduleName, index=statesList[0], amp=statesList[2], decay=statesList[3],
                                    lfoSpeed=statesList[4], lfoAmpl=statesList[5]
                                    )
        self.module.refreshModule()
        self.module.openPattern(statesList[1])
        self.server.addModule(self.module)
        self.modulesBoxSizer.Add(self.module, 0, wx.ALL, 5)
        self.modulesBoxSizer.Layout()
        self.Refresh()
        
    def open(self, evt):
        project = self.server.getProject()
        if project == []:
            dlg = wx.FileDialog(self, "Open File...", style=wx.FD_OPEN)
            if dlg.ShowModal() == wx.ID_OK:
                self.path = dlg.GetPath()
                execfile(self.path, globals())
                self.setStateDictionary(stateDictionary)
                self.refreshTitle()
            dlg.Destroy()
        else:
            pass


    def save(self, evt):
        if not self.path:
            self.saveAs(evt)
        else:
            self.saveFile()

    def saveAs(self, evt):
        self.getStateDictionary()
        dlg = wx.FileDialog(self, "Save File As...", style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
        if dlg.ShowModal() == wx.ID_OK:
            self.path = dlg.GetPath()
            self.saveFile()
        dlg.Destroy()

    def saveFile(self):
        dict = self.getStateDictionary()
        f = open(self.path, "w")
        f.write("stateDictionary = %s" % str(dict))
        f.close()
        self.refreshTitle()
        
    def refreshTitle(self):
        self.SetTitle("TR-3535  - %s" % self.path)
        
    def handleAudio(self, evt):
        if evt.GetInt() == 1:
            self.server.serverStart()
            self.server.controlVolume(self.masterFader.GetValue()/100.)
            self.masterClick.play()
        else:
            self.server.serverStop()
            self.masterClick.stop()

    def changeBpm(self, evt):
        self.bpm.setValue(evt.GetInt())
        
    def createModule(self, evt):
        moduleRank = evt.GetId()-100
        moduleName = self.modules[evt.GetId()-100]
        self.module = InstInterface(self.modulesPanel, metro=self.masterClick, y=moduleRank, type=dict[moduleName], name=moduleName)
        self.server.addModule(self.module)
        self.modulesBoxSizer.Add(self.module, 0, wx.ALL, 5)
        self.modulesBoxSizer.Layout()
        self.Refresh()
        
    def onQuit(self, evt):
        self.server.serverStop()
        self.Destroy()


class InstInterface(wx.Panel):
    def __init__(self, parent, metro, y, type, name, index=0, amp=50, decay=100, lfoSpeed=0, lfoAmpl=0):
        wx.Panel.__init__(self, parent, pos=(0, 0+175*y), size=(800, 175), style=wx.SUNKEN_BORDER)
        self.metro = metro
        self.rank = y
        self.type = type
        self.name = name
        self.morphing = index
        self.volume = amp
        self.decay = decay
        self.lfoSpeed = lfoSpeed
        self.lfoAmpl = lfoAmpl

        self.instName = wx.StaticText(self, id=-1, label=self.name, pos=(370, 0), size=wx.DefaultSize)

        self.volumeText = wx.StaticText(self, id=-1, label="Volume", pos=(20, 40), size=wx.DefaultSize)
        self.volumeFader = wx.Slider(self, id=-1, value=self.volume, minValue=0, maxValue=100, pos=(75, 40), size=(100, 25))
        self.volumeFader.Bind(wx.EVT_SLIDER, self.changeVolume)

        self.decayText = wx.StaticText(self, id=-1, label="Decay", pos=(200, 40), size=wx.DefaultSize)
        self.decayFader = wx.Slider(self, id=-1, value=self.decay, minValue=25, maxValue=200, pos=(255,40), size=(100, 25))
        self.decayFader.Bind(wx.EVT_SLIDER, self.changeDecay)
        
        self.lfoSpeedText = wx.StaticText(self, id=-1, label="Lfo Speed", pos=(415, 40), size=wx.DefaultSize)
        self.lfoSpeedFader = wx.Slider(self, id=-1, value=self.lfoSpeed, minValue=0, maxValue=300, pos=(480, 40), size=(100, 25))
        self.lfoSpeedFader.Bind(wx.EVT_SLIDER, self.changeLfoFreq)

        self.lfoAmplText = wx.StaticText(self, id=-1, label="Lfo Amplitude", pos=(595, 40), size=wx.DefaultSize)
        self.lfoAmplFader = wx.Slider(self, id=-1, value=self.lfoAmpl, minValue=0, maxValue=100, pos=(695, 40), size=(100, 25))
        self.lfoAmplFader.Bind(wx.EVT_SLIDER, self.changeLfoAmpl)

        self.sixButton = wx.Button(self, id=-1, label="tr-606", pos=(5, 80), size=(-1, -1))
        self.sixButton.Bind(wx.EVT_BUTTON, self.goSix)
        self.sevenButton = wx.Button(self, id=-1, label="tr-707", pos=(245, 80), size=(-1, -1))
        self.sevenButton.Bind(wx.EVT_BUTTON, self.goSeven)
        self.eightButton = wx.Button(self, id=-1, label="tr-808", pos=(490, 80), size=(-1, -1))
        self.eightButton.Bind(wx.EVT_BUTTON, self.goEight)
        self.nineButton = wx.Button(self, id=-1, label="tr-909", pos=(730, 80), size=(-1, -1))
        self.nineButton.Bind(wx.EVT_BUTTON, self.goNine)
        self.instSlider = wx.Slider(self, id=-1, value=self.morphing, minValue=1, maxValue=8192, pos=(25, 115), size=(750, 25))
        self.instSlider.Bind(wx.EVT_SLIDER, self.morphInst)

        #interface sequenceur
        self.measure = []
        self.playNote = [self.firstFirst, self.firstSecond, self.firstThird, self.firstFourth,
                        self.secondFirst, self.secondSecond, self.secondThird, self.secondFourth,
                        self.thirdFirst, self.thirdSecond, self.thirdThird, self.thirdFourth,
                        self.fourthFirst, self.fourthSecond, self.fourthThird, self.fourthFourth]
        self.buttons = []
        for i in range (16):
            self.sixteenth = wx.ToggleButton(self, id=-1, label="%d" %(i+1), pos=((25*i)+(25*i+15), 150), size=(25, 25))
            self.buttons.append(self.sixteenth)
            self.measure.append(0)
            self.sixteenth.Bind(wx.EVT_TOGGLEBUTTON, self.playNote[i])
            
        self.instrument = InstGenerator(
                                        dictionary=self.type, list=self.measure, tempo=self.metro, index=self.morphing, amp=self.volume/100.,
                                        dec=self.decay/100., lfoFreq=self.lfoSpeed, lfoMul=self.lfoAmpl
                                        )
                                        
    def out(self):
        return self.instrument.out()
        
    def refreshModule(self):
        self.instrument.changeAmp(self.volumeFader.GetValue()/100.)
        self.instrument.changeDec(self.decayFader.GetValue()/100.)
        self.instrument.changeLfoFreq(self.lfoSpeedFader.GetValue()/50.)
        self.instrument.changeLfoMul(self.lfoAmplFader.GetValue()/100.)
        
    def getState(self):
        return (self.morphing, self.measure, self.volume, self.decay, self.lfoSpeed, self.lfoAmpl)
        
    def changeVolume(self, evt):
        self.volume = evt.GetInt()
        self.instrument.changeAmp(evt.GetInt()/100.)
        
    def changeDecay(self, evt):
        self.decay = evt.GetInt()
        self.instrument.changeDec(evt.GetInt()/100.)
        
    def changeLfoFreq(self, evt):
        self.lfoSpeed = evt.GetInt()
        self.instrument.changeLfoFreq(evt.GetInt()/50.)

    def changeLfoAmpl(self, evt):
        self.lfoAmpl = evt.GetInt()
        self.instrument.changeLfoMul(evt.GetInt()/100.)
 
    def morphInst(self, evt):
        self.morphing = evt.GetInt()
        self.instrument.morphTables(self.morphing)
        
    def goSix(self, evt):
        self.instrument.morphTables(0)
        self.instSlider.SetValue(0)
        
    def goSeven(self, evt):
        self.instrument.morphTables(2730)
        self.instSlider.SetValue(2730)
        
    def goEight(self, evt):
        self.instrument.morphTables(5461)
        self.instSlider.SetValue(5461)
        
    def goNine(self, evt):
        self.instrument.morphTables(8192)
        self.instSlider.SetValue(8192)
        
    def openPattern(self, newList):
        self.measure = newList
        for i in range(len(self.measure)):
            if self.measure[i] == 1:
                self.buttons[i].SetValue(1)
            if self.measure[i] == 0:
                self.buttons[i].SetValue(0)
        self.instrument.editMeasure(self.measure)
        
    def firstFirst(self, evt):
        if evt.GetInt() == 1:
            self.measure[0] = 1
            self.instrument.editMeasure(self.measure)
        else:
            self.measure[0] = 0
            self.instrument.editMeasure(self.measure)
            
    def firstSecond(self, evt):
        if evt.GetInt() == 1:
            self.measure[1] = 1
            self.instrument.editMeasure(self.measure)
        else:
            self.measure[1] = 0
            self.instrument.editMeasure(self.measure)
    
    def firstThird(self, evt):
        if evt.GetInt() == 1:
            self.measure[2] = 1
            self.instrument.editMeasure(self.measure)
        else:
            self.measure[2] = 0
            self.instrument.editMeasure(self.measure)
    def firstFourth(self, evt):
        if evt.GetInt() == 1:
            self.measure[3] = 1
            self.instrument.editMeasure(self.measure)
        else:
            self.measure[3] = 0
            self.instrument.editMeasure(self.measure)
                 
    def secondFirst(self, evt):
        if evt.GetInt() == 1:
            self.measure[4] = 1
            self.instrument.editMeasure(self.measure)
        else:
            self.measure[4] = 0
            self.instrument.editMeasure(self.measure)
                 
    def secondSecond(self, evt):
        if evt.GetInt() == 1:
            self.measure[5] = 1
            self.instrument.editMeasure(self.measure)
        else:
            self.measure[5] = 0
            self.instrument.editMeasure(self.measure)
                 
    def secondThird(self, evt):
        if evt.GetInt() == 1:
            self.measure[6] = 1
            self.instrument.editMeasure(self.measure)
        else:
            self.measure[6] = 0
            self.instrument.editMeasure(self.measure)
                 
    def secondFourth(self, evt):
        if evt.GetInt() == 1:
            self.measure[7] = 1
            self.instrument.editMeasure(self.measure)
        else:
            self.measure[7] = 0
            self.instrument.editMeasure(self.measure)
                 
    def thirdFirst(self, evt):
        if evt.GetInt() == 1:
            self.measure[8] = 1
            self.instrument.editMeasure(self.measure)
        else:
            self.measure[8] = 0
            self.instrument.editMeasure(self.measure)
                 
    def thirdSecond(self, evt):
        if evt.GetInt() == 1:
            self.measure[9] = 1
            self.instrument.editMeasure(self.measure)
        else:
            self.measure[9] = 0
            self.instrument.editMeasure(self.measure)
                 
    def thirdThird(self, evt):
        if evt.GetInt() == 1:
            self.measure[10] = 1
            self.instrument.editMeasure(self.measure)
        else:
            self.measure[10] = 0
            self.instrument.editMeasure(self.measure)
                 
    def thirdFourth(self, evt):
        if evt.GetInt() == 1:
            self.measure[11] = 1
            self.instrument.editMeasure(self.measure)
        else:
            self.measure[11] = 0
            self.instrument.editMeasure(self.measure)
                 
    def fourthFirst(self, evt):
        if evt.GetInt() == 1:
            self.measure[12] = 1
            self.instrument.editMeasure(self.measure)
        else:
            self.measure[12] = 0
            self.instrument.editMeasure(self.measure)
                 
    def fourthSecond(self, evt):
        if evt.GetInt() == 1:
            self.measure[13] = 1
            self.instrument.editMeasure(self.measure)
        else:
            self.measure[13] = 0
            self.instrument.editMeasure(self.measure)
                 
    def fourthThird(self, evt):
        if evt.GetInt() == 1:
            self.measure[14] = 1
            self.instrument.editMeasure(self.measure)
        else:
            self.measure[14] = 0
            self.instrument.editMeasure(self.measure)
                 
    def fourthFourth(self, evt):
        if evt.GetInt() == 1:
            self.measure[15] = 1
            self.instrument.editMeasure(self.measure)
        else:
            self.measure[15] = 0
            self.instrument.editMeasure(self.measure)